<html>
<head>
<link rel="shortcut icon" href="./favicon.ico">
<link rel="stylesheet" type="text/css" href="./style.css">
<link rel="canonical" href="./RAM_Simple_Dual_Port_Dual_Clock.html">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="Defines a memory, of various implementation, with one write port and one read port (1W1R), separately addressed, *each with its own, asynchronous clock.*  Common data width on both ports. Since the clocks are asynchronous, there can be no write-forwarding during coincident reads and writes.">
<title>RAM Simple Dual Port Dual Clock</title>
</head>
<body>

<p class="inline bordered"><b><a href="./RAM_Simple_Dual_Port_Dual_Clock.v">Source</a></b></p>
<p class="inline bordered"><b><a href="./legal.html">License</a></b></p>
<p class="inline bordered"><b><a href="./index.html">Index</a></b></p>

<h1>Simple Dual-Ported RAM (Dual Clock)</h1>
<p>Defines a memory, of various implementation, with one write port and one
 read port (1W1R), separately addressed, <em>each with its own, asynchronous
 clock.</em>  Common data width on both ports. Since the clocks are
 asynchronous, there can be no write-forwarding during coincident reads and
 writes.</p>
<p>There is no synchronous clear on the read output: In Quartus at least, any
 register driving it cannot be retimed, and it may not be as portable.
 Instead, use separate logic (e.g.: an <a href="./Annuller.html">Annuller</a>) to
 zero-out the read output down the line.</p>
<p><em>This module is a variation on the single-clocked <a href="./RAM_Simple_Dual_Port.html">Simple Dual Port
 RAM</a>.</em></p>

<pre>
`default_nettype none

module <a href="./RAM_Simple_Dual_Port_Dual_Clock.html">RAM_Simple_Dual_Port_Dual_Clock</a>
#(
    parameter                       WORD_WIDTH          = 0,
    parameter                       ADDR_WIDTH          = 0,
    parameter                       DEPTH               = 0,
    // Used as an attribute, not a value
    // verilator lint_off UNUSED
    parameter                       RAMSTYLE            = "",
    // verilator lint_on  UNUSED
    parameter                       USE_INIT_FILE       = 0,
    parameter                       INIT_FILE           = "",
    parameter   [WORD_WIDTH-1:0]    INIT_VALUE          = 0
)
(
    input  wire                         write_clock,
    input  wire                         wren,
    input  wire     [ADDR_WIDTH-1:0]    write_addr,
    input  wire     [WORD_WIDTH-1:0]    write_data,

    input  wire                         read_clock,
    input  wire                         rden,
    input  wire     [ADDR_WIDTH-1:0]    read_addr, 
    output reg      [WORD_WIDTH-1:0]    read_data
);

    initial begin
        read_data = {WORD_WIDTH{1'b0}};
    end
</pre>

<h2>RAM Memory</h2>
<p>Set the ram style to control implementation.
 See your CAD tool documentation for available options.</p>
<p>For Quartus, to remove inference of write-forwarding, at the price of
 indeterminate behaviour on coincident read/writes, use "no_rw_check" as
 part of the RAMSTYLE (e.g.: "M10K, no_rw_check").  If that fails, add this
 setting to your Quartus project: <code>set_global_assignment -name
 ADD_PASS_THROUGH_LOGIC_TO_INFERRED_RAMS OFF</code> to disable creation of
 write-forwarding logic, as Quartus ignores the "no_rw_check" RAMSTYLE for
 M10K BRAMs.</p>

<pre>
    (* ramstyle  = RAMSTYLE *) // Quartus
    (* ram_style = RAMSTYLE *) // Vivado
</pre>

<p>Vivado uses a different mechanism to control write-forwarding: we must set
 RW_ADDR_COLLISION to "no to prevent the inference of write forwarding
 logic, which is meaningless when the read and write clocks are
 asynchronous.</p>

<pre>
    (* rw_addr_collision = "no" *) // Vivado
</pre>

<p>This is the RAM array proper. It is initialized later.</p>

<pre>
    reg [WORD_WIDTH-1:0] ram [DEPTH-1:0];
</pre>

<h2>Read and Write Ports</h2>
<p>The read and write ports operate each on their own clocks. In the limit
 case of having synchronous clocks and coincident reads and writes, there
 will be no write-forwarding: the read port will return the data currently
 in the RAM, not the value of the read.</p>

<pre>
    always @(posedge write_clock) begin
        if(wren == 1'b1) begin
            ram[write_addr] <= write_data;
        end
    end

    always @(posedge read_clock) begin
        if(rden == 1'b1) begin
            read_data <= ram[read_addr];
        end
    end
</pre>

<h2>Memory Initialization</h2>
<p>If you are not using an init file, the following code will set all memory
 locations to INIT_VALUE. The CAD tool should generate a memory
 initialization file from that.  This is useful to cleanly implement small
 collections of registers (e.g.: via RAMSTYLE = "logic" on Quartus), without
 having to deal with an init file.  Your CAD tool may complain about too
 many for-loop iterations if your memory is very deep. Adjust the tool
 settings to allow more loop iterations.</p>
<p>At a minimum, the initialization file format is one value per line, one for
 each memory word from 0 to DEPTH-1, in bare hexadecimal (e.g.: 0012 to init
 a 16-bit memory word with 16'h12). Note that if your WORD_WIDTH isn't
 a multiple of 4, the CAD tool may complain about the width mismatch.
 You can base yourself on this Python <a href="./RAM_generate_empty_init_file.py">memory initialization file
 generator</a>.</p>

<pre>
    generate
        if (USE_INIT_FILE == 0) begin
            integer i;
            initial begin
                for (i = 0; i < DEPTH; i = i + 1) begin
                    ram[i] = INIT_VALUE;
                end
            end
        end
        else begin
            initial begin
                $readmemh(INIT_FILE, ram);
            end
        end
    endgenerate

endmodule
</pre>

<hr>
<p><a href="./index.html">Back to FPGA Design Elements</a>
<center><a href="https://fpgacpu.ca/">fpgacpu.ca</a></center>
</body>
</html>

